Skip to content

[PANA-5681] Preparation for Heatmaps cross-platform integration#3549

Open
jonathanmos wants to merge 4 commits into
feature/heatmapsfrom
jmoskovich/pana-5681/heatmaps-crossplatform-prep
Open

[PANA-5681] Preparation for Heatmaps cross-platform integration#3549
jonathanmos wants to merge 4 commits into
feature/heatmapsfrom
jmoskovich/pana-5681/heatmaps-crossplatform-prep

Conversation

@jonathanmos

@jonathanmos jonathanmos commented Jun 17, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Reorganise heatmap types into correct packages

Public declarations (CrossPlatformHeatmapActionData, HeatmapIdentifierRegistryProvider, heatmapViewKey) are moved out of com.datadog.android.internal.heatmaps, since public types must not live in a package named internal. isValidTapTarget was moved out of heatmaps since it is a general util.

HeatmapActionData is split into two distinct types:

NativeHeatmapActionData — carries a viewKey (a composite identity hash of the tapped View and its parent), used to look up a pre-computed identifier from the HeatmapIdentifierRegistry that Session Replay populated during its last traversal.
CrossPlatformHeatmapActionData — carries an elementPath (a list of string path segments) and viewUrl, from which the identifier is computed on demand at action-send time via HeatmapIdentifier.create().
HeatmapActionResolver and NativeHeatmapActionData are also moved from rum.internal.domain.scope (where they are not scope concepts) to the dedicated rum.internal.heatmaps package.

Add cross-platform heatmap tap action support

Exposes two new methods on _RumInternalProxy for cross-platform SDKs (React Native, etc.):

getCurrentViewUrl() — returns the URL of the currently active RUM view. Cross-platform SDKs must call this at tap time and use the result as both the screen name for Session Replay wireframe identifier computation and the viewUrl field of CrossPlatformHeatmapActionData.
addActionWithHeatmap() — records a tap action with heatmap data attached. The Android SDK validates that the view URL captured at tap time still matches the active view at action-send time, dropping the heatmap data (with a developer-facing warning) if navigation has occurred in between.

Motivation

Heatmaps on Android currently only work with native gesture tracking. This PR lays the foundation for cross-platform SDKs to emit heatmap-tagged tap actions, enabling heatmap features in React Native and future cross-platform targets.

Additional Notes

getCurrentViewUrl() reads from a volatile cached field updated after each RUM event, making it safe to call from the UI thread without blocking on the RUM executor.
The view URL mismatch guard in HeatmapActionResolver.CrossPlatform handles the inherent race between a tap on screen A and a navigation to screen B: if the view has changed by the time the action is processed, the heatmap data is dropped rather than attributed to the wrong screen.
Identifier computation for cross-platform actions uses the same HeatmapIdentifier.create() path as Session Replay, ensuring the resulting permanentId matches the wireframe identifier SR computed for the same element.

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

@datadog-prod-us1-5

This comment has been minimized.

@jonathanmos jonathanmos force-pushed the jmoskovich/pana-5681/heatmaps-crossplatform-prep branch from 3aa612d to 200cd05 Compare June 17, 2026 14:38
@codecov-commenter

codecov-commenter commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.56863% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.22%. Comparing base (aea05eb) to head (6784792).
⚠️ Report is 2 commits behind head on feature/heatmaps.

Files with missing lines Patch % Lines
...oid/rum/internal/heatmaps/HeatmapActionResolver.kt 79.07% 7 Missing and 2 partials ⚠️
...android/heatmaps/CrossPlatformHeatmapActionData.kt 0.00% 7 Missing ⚠️
...dog/android/internal/heatmaps/HeatmapIdentifier.kt 45.45% 6 Missing ⚠️
...ndroid/rum/internal/domain/scope/RumActionScope.kt 50.00% 4 Missing and 2 partials ⚠️
...lay/internal/recorder/HeatmapIdentifierResolver.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@                 Coverage Diff                  @@
##           feature/heatmaps    #3549      +/-   ##
====================================================
+ Coverage             72.19%   72.22%   +0.03%     
====================================================
  Files                   970      972       +2     
  Lines                 35668    35751      +83     
  Branches               5937     5944       +7     
====================================================
+ Hits                  25748    25820      +72     
- Misses                 8289     8312      +23     
+ Partials               1631     1619      -12     
Files with missing lines Coverage Δ
...ava/com/datadog/android/heatmaps/HeatmapViewKey.kt 100.00% <ø> (ø)
...m/datadog/android/internal/utils/TapTargetUtils.kt 100.00% <ø> (ø)
...rum/src/main/kotlin/com/datadog/android/rum/Rum.kt 86.42% <100.00%> (+0.17%) ⬆️
...otlin/com/datadog/android/rum/_RumInternalProxy.kt 68.00% <100.00%> (+2.78%) ⬆️
...lin/com/datadog/android/rum/internal/RumFeature.kt 92.81% <ø> (-0.23%) ⬇️
...g/android/rum/internal/domain/scope/RumRawEvent.kt 100.00% <100.00%> (ø)
...d/rum/internal/heatmaps/NativeHeatmapActionData.kt 100.00% <100.00%> (ø)
...entation/gestures/AndroidActionTrackingStrategy.kt 94.44% <ø> (ø)
...ernal/instrumentation/gestures/GesturesListener.kt 93.71% <100.00%> (ø)
.../android/rum/internal/monitor/DatadogRumMonitor.kt 87.87% <100.00%> (+0.69%) ⬆️
... and 7 more

... and 41 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jonathanmos jonathanmos force-pushed the jmoskovich/pana-5681/heatmaps-crossplatform-prep branch from 44134c3 to 35813a5 Compare June 18, 2026 08:13
@jonathanmos jonathanmos force-pushed the jmoskovich/pana-5681/heatmaps-crossplatform-prep branch from 35813a5 to 893e43f Compare June 18, 2026 08:21
@jonathanmos jonathanmos marked this pull request as ready for review June 18, 2026 10:31
@jonathanmos jonathanmos requested review from a team as code owners June 18, 2026 10:31

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6784792bdf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
}

override fun getCurrentViewUrl(): String? = cachedViewUrl

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return a fresh view URL for queued view changes

When a cross-platform SDK calls getCurrentViewUrl() immediately after a startView/navigation event, that view change has only been enqueued through handleEvent/withWriteContext; cachedViewUrl is not updated until the RUM executor later reaches updateCachedViewUrl. This can return the previous URL or null, and the subsequent addActionWithHeatmap() is later resolved against the newly processed view, causing the mismatch guard to drop otherwise valid heatmap data. Consider updating this cache when queuing view changes or exposing a synchronous read that accounts for pending events.

Useful? React with 👍 / 👎.

@jonathanmos jonathanmos Jun 18, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The race window here is real but narrow, and the viewurl check already handles it. The purpose of viewUrl is to ensure the hash is computed with the same URL string Session Replay is using — so if cachedViewUrl is stale and we let the action through, we'd produce a hash that would risk a misleading correlation. The guard dropping the data in that case isn't data loss, it's the right outcome. Taps that land at the exact moment of navigation are inherently ambiguous. I'll add a comment to getCurrentViewUrl() explaining this, but I don't think a code change is warranted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants